#include <SDL/SDL.h>

#include <SDL/SDL_opengl.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include "expression/interface.h"
#include "expression/Expressions.h"
#include "render/Scene.h"
#include "render/Basis.h"
#include "render/CustomQuadric.h"

// See : http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html
extern "C" {
	extern int yyparse();
	extern FILE* yyin;
}

#define WINDOW_W 640
#define WINDOW_H 480

// Global TODO : const methods when needed ?
int main(int argc, char *argv[])
{
	SDL_Event event;
    SDL_Init(SDL_INIT_VIDEO);
    atexit(SDL_Quit);
    SDL_WM_SetCaption("SDL GL Application", NULL);
    SDL_SetVideoMode(WINDOW_W, WINDOW_H, 32, SDL_OPENGL);

	// Keyboard unicode (azerty / qwerty no differenciation)
	SDL_EnableUNICODE(1);

	// Mouse stuff
	SDL_WM_GrabInput(SDL_GRAB_ON);
	SDL_WarpMouse(WINDOW_W/2, WINDOW_H/2);
    SDL_ShowCursor(SDL_DISABLE);
    SDL_EnableKeyRepeat(10,10);

    // Parsing
	if(argc<2)
		return 1;
	yyin = fopen(argv[1], "r");
	if(yyin == NULL || yyparse())
		return 1;
	else
		fclose(yyin);
	

    // Declare scene AFTER SDL initialisation
    // Near must NOT be set to 0. See : http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml
    Scene scene(70, WINDOW_W/WINDOW_H, 0.1, 1000, Vector3(3,3,3), Vector3(0,0,0), Vector3(0,1,0));

	Basis* basis = new Basis(Vector3(0,0,0), 1.0, Color(255, 255, 255));
	scene.addObject(basis);

	Expression* exp = (Expression*)getRoot();
	Expression* deltaTheta = (Expression*)getDeltaTheta();
	Expression* deltaPhi = (Expression*)getDeltaPhi();
	CustomQuadric* quadric = new CustomQuadric(Vector3(0,0,0), exp, deltaTheta, deltaPhi);
	scene.addObject(quadric);

	Expression* rgb[3] = {(Expression*)getRgb()[0], (Expression*)getRgb()[1], (Expression*)getRgb()[2]};
	quadric->SetColor(rgb);
	quadric->Calculate();

    for (;;)
    {
        SDL_PollEvent(&event);

        switch(event.type)
        {
            case SDL_QUIT:
            exit(0);
            case SDL_KEYUP:
            if(event.key.keysym.sym == SDLK_ESCAPE)
            	exit(0);
            else
            	scene.TreatEvent(event);
            break;
            default:
            scene.TreatEvent(event);
        }
        scene.Render();

    }

    return 0;
}
